package akbderby.page;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

import org.slim3.controller.Navigation;
import org.slim3.datastore.Datastore;

import scenic3.annotation.ActionPath;
import scenic3.annotation.Default;
import scenic3.annotation.Page;
import scenic3.annotation.Var;
import akbderby.model.Blobstore;
import akbderby.model.UserData;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

@Page("/derby")
public class DerbyPage extends BasePage {

    // private UploadService service = new UploadService();

    @ActionPath("start/{limit}")
    public Navigation start(@Var("limit") int limit) {

        UserData userData = getUser();
        userData.setTotalGets(0);

        List<Blobstore> dataList = Datastore.query(Blobstore.class).asList();
        for (Blobstore data : dataList) {
            data.setFinished(false);
            data.setClick(0);
            data.setRank(0);
            data.setPoint(0);
        }
        dataList = randomOrder(dataList, limit);
        Blobstore blobstore = dataList.get(0);
        blobstore.setFinished(true);
        sessionScope("currentData", blobstore);
        sessionScope("dataList", dataList);
        sessionScope("rankingList", new ArrayList<Blobstore>(dataList.size()));

        sessionScope("currentNumber", Integer.valueOf(0));
        sessionScope("totalNumber", dataList.size() - 1);
        return redirect(basePath);
    }

    @ActionPath("add/{id}")
    public Navigation add(@Var("id") String id) {
        Key key = KeyFactory.stringToKey(id);
        Blobstore blobstore = Datastore.get(Blobstore.class, key);
        sessionScope("girlfriend", blobstore);

        UserData userData = getUser();
        if (userData.isAuthentication()) {
            userData.setGirlFriendId(id);
            Datastore.put(userData);
        }

        return redirect("/derby/end");
    }

    @ActionPath("select/{id}")
    public Navigation select(@Var("id") String id) throws Exception {
        int addPoint = 0;
        String lostId = "";
        if ("varsusData".equals(id)) {
            lostId = "currentData";
        } else {
            lostId = "varsusData";
        }
        Blobstore lostData = sessionScope(lostId);
        List<Blobstore> rankingList = sessionScope("rankingList");
        rankingList.add(lostData);
        if ("currentData".equals(lostId)) {
            addPoint = lostData.getPoint();
        }

        Blobstore blobstore = sessionScope(id);
        blobstore.setCount(blobstore.getCount() + 1);
        blobstore.setClick(blobstore.getClick() + 1);
        blobstore.setPoint(blobstore.getPoint() + 1 + addPoint);
        Datastore.put(blobstore);
        sessionScope("currentData", blobstore);

        UserData userData = getUser();
        userData.setTotalGets(userData.getTotalGets() + blobstore.getCount());

        return redirect(basePath);
    }

    @ActionPath("end")
    public Navigation end() throws Exception {
        // TODO マニアクイズもいいかも
        List<Blobstore> rankingList = sessionScope("rankingList");
        Collections.sort(rankingList, new PointComparator());

        List<Blobstore> tmpList = new ArrayList<Blobstore>();
        for (int i = 0; i < rankingList.size(); i++) {
            tmpList.add(rankingList.get(i));
            if (i >= 9)
                break;
        }

        int rank = 1;
        int click = 0;
        boolean first = true;
        for (Blobstore blobstore : tmpList) {
            if (!first && click != blobstore.getClick()) {
                rank++;
            }
            first = false;
            blobstore.setRank(rank);
            click = blobstore.getClick();
        }
        requestScope("rankingList", tmpList);

        // 得点
        UserData userData = getUser();
        requestScope("totalGet", userData.getTotalGets());

        if (userData.isAuthentication()) {
            userData.setPoint(userData.getPoint() + userData.getTotalGets());
            Datastore.put(userData);
        }

        return forward("/derby/end.jsp");
    }

    @Default
    public Navigation index() {
        List<Blobstore> dataList = sessionScope("dataList");

        if (dataList == null || dataList.isEmpty()) {
            return redirect("/derby/end");
        }

        requestScope("vs1", sessionScope("currentData"));
        Blobstore blobstore = null;
        for (Blobstore data : dataList) {
            if (!data.isFinished()) {
                blobstore = data;
                blobstore.setFinished(true);
                break;
            }
        }
        if (blobstore == null) {
            List rankingList = sessionScope("rankingList");
            rankingList.add(sessionScope("currentData"));
            return redirect("/derby/end");
        }
        requestScope("vs2", blobstore);
        sessionScope("varsusData", blobstore);

        sessionScope(
            "currentNumber",
            ((Integer) sessionScope("currentNumber")) + 1);
        return forward("/derby/selection.jsp");
    }

    private List<Blobstore> randomOrder(List<Blobstore> list, int limit) {
        List<Blobstore> tmpList = new ArrayList<Blobstore>(list.size());
        Random random = new Random();

        while (list.size() > 0) {
            int r = random.nextInt(list.size());
            tmpList.add(list.remove(r));
        }
        int size = 0;
        for (Blobstore object : tmpList) {
            if (limit > 0 && size > limit)
                break;
            list.add(object);
            size++;
        }
        return list;
    }

    private List<Blobstore> getLimitedList(List<Blobstore> list, int limit) {
        List<Blobstore> returnList = new ArrayList<Blobstore>(list.size());
        int size = 0;
        for (Blobstore object : list) {
            if (limit > 0 && size > limit)
                break;
            returnList.add(object);
            size++;
        }
        return returnList;
    }

    private class PointComparator implements Comparator<Blobstore> {
        public int compare(Blobstore o1, Blobstore o2) {
            int o1Point = o1.getPoint();
            int o2Point = o2.getPoint();
            if (o1Point > o2Point)
                return -1;
            if (o1Point < o2Point)
                return 1;

            int o1Count = o1.getCount();
            int o2Count = o2.getCount();
            if (o1Count > o2Count)
                return -1;
            if (o1Count < o2Count)
                return 1;
            return 0;
        }
    }

    private class CountComparator implements Comparator<Blobstore> {
        public int compare(Blobstore o1, Blobstore o2) {
            int o1Count = o1.getCount();
            int o2Count = o2.getCount();
            if (o1Count > o2Count)
                return -1;
            if (o1Count < o2Count)
                return 1;
            return 0;
        }
    }
}
